//
//  NSString+XXTes.m
//  PhotoAlbum
//
//  Created by Anton Remizov on 29.03.12.
//  Copyright (c) 2012 Mediaparts Interactive. All rights reserved.
//

#import "NSString+XXTea.h"
#import "NSData+Base64.h"

@implementation NSString(XXTea)

- (void) charsToLongs:(const char*)cStr to:(long*)temp ofLength:(int)length includeLength:(BOOL)includeLength
{
	int len = ceil(length/4.0) - 1;
    //	if(includeLength)
    //		--len;
    
	int i;
	for (i = 0; i < len; i++) 
	{	
		temp[i] = 0;
		for(int j = 0; j < 4; ++j)
		{
			long l = cStr[i*4 + j]&0x000000FF;
			temp[i]+=l<<(8*j);
		}
	}
	temp[i] = 0;
	for(int k = 0; k < length-i*4; ++k)
	{
		long l = cStr[i*4+k]&0x000000FF;
		temp[i] += l<<(8*k);
	}
	
	temp[i + 1] = length;	
}

- (void) longsToChars:(long*)longs to:(char*)cStr ofLength:(int)length includeLength:(BOOL)includeLength
{
	int len = includeLength?(length - 1):length;
    
	for (int i = 0; i < len; i++) 
	{
		cStr[i*4 + 0] = longs[i] & 0xFF;
		cStr[i*4 + 1] = longs[i]>>8 & 0xFF;
		cStr[i*4 + 2] = longs[i]>>16 & 0xFF;
		cStr[i*4 + 3] = longs[i]>>24 & 0xFF;
	}
}

- (NSString*) charsToHex:(const char*)str withLength:(int)length
{
	NSMutableString* result = [NSMutableString string];
	char hexes[] = {'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'};
	for (int i = 0; i<length; i++) {
		Byte b = str[i];
		[result appendFormat:@"%c%c",hexes[b >> 4],hexes[b & 0xf]];
	}
	return result;
}

- (char) longFromHexChar:(char)c
{
	switch (c) {
		case '0': return 0;
		case '1': return 1;
		case '2': return 2;
		case '3': return 3;
		case '4': return 4;
		case '5': return 5;
		case '6': return 6;
		case '7': return 7;
		case '8': return 8;
		case '9': return 9;
		case 'a': return 0xa;
		case 'b': return 0xb;
		case 'c': return 0xc;
		case 'd': return 0xd;
		case 'e': return 0xe;
		case 'f': return 0xf;
		default:  return 0;
	}
}

- (void) hex:(const char*)hexStr to:(char*)array length:(int)length
{
	int k = 0;
	NSUInteger i = 0;
	if(hexStr[0] == '0' && hexStr[1] == 'x') i+=2;
	for(;i < length; i+=2)
	{
		char c1 = hexStr[i];
		char c2 = hexStr[i + 1];
		unsigned char n1 = [self longFromHexChar:c1] << 4;
		unsigned char n2 = [self longFromHexChar:c2];
		array[k++] = n1 | n2;
	}
}

- (NSString*) XXTEAEncryptWithKey:(NSString*)key
{
	const char* cStr = [self UTF8String];
    //	const char* cStr =[[str dataUsingEncoding:NSUTF8StringEncoding] bytes];
	const char* cKey = [key UTF8String];
	int strLength = (int)strlen(cStr);
	int keyLength = (int)strlen(cKey);
	int n = ceil((float)strLength/4.0) + 1;//length + 1 because (include length == true)
	int kLength = ceil((float)keyLength/4.0);
	
	uint32_t v[n];
	uint32_t k[kLength];
	
	[self charsToLongs:cStr to:(long*)v ofLength:strLength includeLength:false];		
	[self charsToLongs:cKey to:(long*)k ofLength:keyLength includeLength:false];
    
	int p;
	if (n == 0) return @"";
	if (n == 1) v[n++] = 0;
	uint32_t z = v[n-1];
	uint32_t y;// = v[0];
	uint32_t delta = 0x9e3779b9;
	uint32_t mx;
	uint32_t e;
	uint32_t q = floor(6+52.0/n);
	uint32_t sum = 0;
	
	while (q-- > 0) 
	{
		sum += delta;
		e = sum>>2 & 3;
		for (p = 0; p<n-1; p++) {
			y = v[p+1];
			mx = (z>>5^y<<2)+(y>>3^z<<4)^(sum^y)+(k[p&3^e]^z);
			z = v[p] += mx;
		}
		y = v[0];
		mx = (z>>5^y<<2)+(y>>3^z<<4)^(sum^y)+(k[p&3^e]^z);
		z = v[n-1] += mx;
	}
	
	char newString[n*4];
	
	[self longsToChars:(long*)v to:newString ofLength:n includeLength:false];	
	NSData* result = [[[NSData alloc] initWithBytes:newString length:n*4] autorelease];
	return [result base64EncodedString];
}

- (NSString*) XXTEADecryptWithKey:(NSString*)key
{
	const char* cKey = [key UTF8String];
	int keyLength = (int)strlen(cKey);
	
	NSData* data = [NSData dataFromBase64String:self];
    //	NSData* data = [NSData dataByBase64DecodingString:str];
	const char* cStr = [data bytes];
	int strLength = (int)[data length];
    //	[self printArray:cStr ofLength:strLength];
	
	int n = ceil((float)strLength/4.0);
	int kLength = ceil((float)keyLength/4.0);
	
	uint32_t v[n];
	uint32_t k[kLength];
	
	[self charsToLongs:cStr to:(long*)v ofLength:strLength includeLength:false];
	[self charsToLongs:cKey to:(long*)k ofLength:keyLength includeLength:false];
	
	int p;
	if (n == 0) return @"";
	
	uint32_t z;// = v[n-1];
	uint32_t y = v[0];
	uint32_t delta = 0x9e3779b9;
	uint32_t mx;
	uint32_t e;
	uint32_t q = floor(6+52.0/n);
	uint32_t sum = q*delta;
	
	while (sum != 0) {
		e = sum>>2 & 3;
		for(p = n-1; p > 0; p--){
			z = v[p-1];
			mx = (z>>5^y<<2)+(y>>3^z<<4)^(sum^y)+(k[p&3^e]^z);
			y = v[p] -= mx;
		}
		z = v[n-1];
		mx = (z>>5^y<<2)+(y>>3^z<<4)^(sum^y)+(k[p&3^e]^z);
		y = v[0] -= mx;
		sum -= delta;
	}
    
	char newString[(n-1)*4];
	[self longsToChars:(long*)v to:newString ofLength:n includeLength:true];	
	return [[[NSString alloc] initWithData: [NSData dataWithBytes:newString length:(n-1)*4] encoding:NSUTF8StringEncoding] autorelease];
}

@end
